class Compiler {
    constructor (vm) {
        this.el = vm.$el;
        this.vm  = vm;
        this.compile(this.el)
    }
    // 编译模板，处理文本节点和元素节点
    compile (el) {
        let childNodes = el.childNodes;
        Array.from(childNodes).forEach(node => {
            if (this.isTextNode(node)) {
                // 处理文本节点
                this.compileText(node)
            } else if (this.isElementNode(node)) {
                // 处理元素节点
                this.compileElement(node)
            }
            // 判断当前节点是否还有子节点，如果有，则递归调用compile进行处理
            if (node.childNodes && node.childNodes.length) {
                this.compile(node);
            }
        });
    }
    // 编译元素节点，处理指令
    compileElement (node) {
        console.dir(node);
        // 遍历所有的属性节点
        const attrs = Array.from(node.attributes);
        attrs.forEach(attr => {
            const attrName = attr.name;
            // 判断所有的属性是否为指令
            if (this.isDirective(attrName)) {
                if (this.directiveType(attrName) === 1) {
                    const eventType = attrName.split(':')[1];
                    const directiveName = attrName.substr(2);
                    const attrValue = attr.value;
                    this.update(directiveName, node, {
                        eventType,
                        attrValue
                    })
                } else if (this.directiveType(attrName) === 2){
                    const attrValue = attr.value; // 指令属性的值，也就是所绑定的数据属性的字段名称
                    const directiveName = attrName.substr(2); // 去除v-之后的指令属性名
                    this.update(directiveName, node, attrValue)
                }
                
            }
        });
    } 
    // 拼接妹子指令所对应的更新视图的方法名，并执行
    update (directiveName, node, key) {
        if (this.directiveType(directiveName) === 1) {
            const directiveFun = this['eventUpdater'];
            console.log('this111 :>> ', this);
            directiveFun && directiveFun.call(this, node, key, {
                eventType: key.eventType,
                method: this.vm.$options.methods[key.attrValue]
            });
        } else {
            const directiveFun = this[`${directiveName}Updater`]
            directiveFun && directiveFun.call(this, node, key, this.vm[key]); // this.vm[attrValue] 所绑定的数据属性的值
        }
        
    }
    // 处理 v-text
    textUpdater(node, key,  value) {
        node.textContent = value
        // 创建Watcher对象，数据改变，试图变更
        new Watcher(this.vm, key, (newValue) => {
            node.textContent = newValue;
        })
    }
    // 处理 v-model
    modelUpdater(node, key, value) {
        node.value = value
        // 创建Watcher对象，数据改变，试图变更
        new Watcher(this.vm, key, (newValue) => {
            node.value = newValue;
        })
        // 双向绑定
        node.addEventListener('input', () => {
            this.vm[key] = node.value;
        });
    }
    // 处理 v-html
    htmlUpdater(node, key,  value) {
        node.innerHTML = value
        // 创建Watcher对象，数据改变，试图变更
        new Watcher(this.vm, key, (newValue) => {
            node.innerHTML = newValue;
        })
    }
    // 处理 v-on
    eventUpdater(node, key,  value) {
        console.log('node, key,  value :>> ', node, key,  value);
        node.addEventListener(key.eventType, () => {
            value.method()
        })
    }
    // 编译文本节点，处理差值表达式
    compileText (node) {
        // console.dir(node); // console.dir 以对象的形式打印
        // 差值表达式 ： {{msg}} 引用的属性的名称和花括号之间可能有0个或多个空格
        const reg = /\{\{(.+?)\}\}/ // 某个特定字符开头及结尾
        const nodeText  = node.textContent;
        if (reg.test(nodeText)) {
            const key  = RegExp.$1.trim()
            node.textContent = nodeText.replace(reg, this.vm[key]);
            // 创建Watcher对象，数据改变，试图变更
            new Watcher(this.vm, key, (newValue) => {
                node.textContent = newValue;
            })
        }
    }
    // 判断元素属性是否是指令
    isDirective (attrName) {
        return attrName.startsWith('v-')
    }
    // 判断指令类型
    directiveType (attrName) {
        if (attrName.indexOf('on') > -1) {
             return 1
        } else {
            return 2
        }
    }
    // 判断节点是否是文本节点
    isTextNode (node) {
        return node.nodeType === 3
    }
    // 判断节点是否是元素节点
    isElementNode (node) {
        return node.nodeType === 1 
    }
  }